#include "qtimreceiverdlg.h"
#include "ui_qtimreceiverdlg.h"
#include "htmlformathelper.h"
#include "../Biz/WWCommonUtility.h"
#include "../Biz/MsgBusParam/IMMessageParam.h"
#include "../Biz/MsgBusParam/IMContactParam.h"
#include "../Core/xparam.hpp"
#include "../Core/SimpleLogger.h"

#include "imsecuritycodedlg.h"
#include "tribemgrdlg.h"

#include <QTime>
#include <QUrl>
#include <QList>
#include <QTimer>
#include <QMessageBox>
#include <QInputDialog>
#include <QCloseEvent>
#include <QFile>
#include <QTextStream>
#include <QFileDialog>
#include <QScrollBar>
#include <QDesktopServices>
#include <QSound>

#include <stdio.h>
using namespace wwcommon;
using namespace wwbiz;
using namespace NetMsgBus;
using namespace core;

#define RECENT_CONTACT_MAX 20

static LoggerCategory g_log("QTIMReceiverDlg");

namespace GlobalData
{
    std::map<std::string, IMUserVerifyInfo> g_all_verifyinfo;
}

using namespace GlobalData;

QTIMReceiverDlg::QTIMReceiverDlg(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::QTIMReceiverDlg),
    phealth_timer(new QTimer(this)),
    pglobal_err_clear_timer(new QTimer(this))
{
    ui->setupUi(this);


    QObject::connect(this, SIGNAL(receiveMsgs(MsgBusParam)), SLOT(OnReceiveMsgs(MsgBusParam)));
    QObject::connect(this, SIGNAL(receiveContacts(MsgBusParam)), SLOT(OnReceiveContacts(MsgBusParam)));

    QObject::connect(this, SIGNAL(receiveAddContactAddedByOther(MsgBusParam)), SLOT(OnReceiveAddContactAddedByOther(MsgBusParam)));
    QObject::connect(this, SIGNAL(receiveAddContactAskAddRequest(MsgBusParam)), SLOT(OnReceiveAddContactAskAddRequest(MsgBusParam)));
    QObject::connect(this, SIGNAL(receiveAddContactDeniedByOther(MsgBusParam)), SLOT(OnReceiveAddContactDeniedByOther(MsgBusParam)));
    QObject::connect(this, SIGNAL(receiveAddContactAgreeAddByOther(MsgBusParam)), SLOT(OnReceiveAddContactAgreeAddByOther(MsgBusParam)));

    QObject::connect(this, SIGNAL(receiveSubscriptionMsg(MsgBusParam)), SLOT(OnReceiveSubscriptionMsg(MsgBusParam)));
    QObject::connect(this, SIGNAL(receiveAuthCodeFailed(std::string)), SLOT(OnReceiveAuthCodeFailed(std::string)));
    //QObject::connect(this, SIGNAL(receiveLogout()), SLOT(OnReceiveLogout()));

    QObject::connect(this, SIGNAL(receiveLoginOK(MsgBusParam)), SLOT(OnReceiveLoginOK(MsgBusParam)), Qt::BlockingQueuedConnection);

    QObject::connect(this, SIGNAL(receiveVerifyUpdate(MsgBusParam)), SLOT(OnReceiveVerifyUpdate(MsgBusParam)));
    QObject::connect(this, SIGNAL(receiveVerifyUpdateForAddContact(MsgBusParam)), SLOT(OnReceiveVerifyUpdateForAddContact(MsgBusParam)));
    QObject::connect(this, SIGNAL(receiveNeedAuthCode(MsgBusParam)), SLOT(OnReceiveNeedAuthCode(MsgBusParam)));

    QObject::connect(ui->text_receive_viewer, SIGNAL(anchorClicked(QUrl)), SLOT(OnAnchorClicked(QUrl)));
    QObject::connect(ui->text_send_viewer, SIGNAL(anchorClicked(QUrl)), SLOT(OnAnchorClicked(QUrl)));
    QObject::connect(ui->sysmsg_output, SIGNAL(anchorClicked(QUrl)), SLOT(OnAnchorClicked(QUrl)));
    QObject::connect(ui->recent_contact_list, SIGNAL(itemActivated(QListWidgetItem*)), SLOT(OnContactListItemClicked(QListWidgetItem*)));
    QObject::connect(ui->all_contact_listwidget, SIGNAL(itemActivated(QListWidgetItem*)), SLOT(OnContactListItemClicked(QListWidgetItem*)));
    QObject::connect(phealth_timer, SIGNAL(timeout()), SLOT(OnHealthCheck()));
    QObject::connect(ui->text_send_btn, SIGNAL(clicked()), SLOT(OnSendMsgClicked()));

    QObject::connect(ui->btnSendFile, SIGNAL(clicked()), SLOT(OnSendFileClicked()));

    QObject::connect(ui->tag_filter_comb, SIGNAL(currentIndexChanged(QString)), SLOT(OnFilterTagChanged(QString)));
    QObject::connect(ui->logout_bt, SIGNAL(clicked()), SLOT(OnDoLogout()));
    QObject::connect(pglobal_err_clear_timer, SIGNAL(timeout()), SLOT(OnGlobalErrClear()));
    QObject::connect(ui->addcontact_btn, SIGNAL(clicked()), SLOT(OnAddContactClicked()));

    QObject::connect(ui->btnHistory, SIGNAL(clicked()), SLOT(OnViewHistoryClicked()));

//    QObject::connect(&logindlg, SIGNAL(DoLogin(std::string, std::string, int)),
//                     SLOT(OnDoLogin(std::string,std::string,int)));
//    QObject::connect(&logindlg, SIGNAL(rejected()), SLOT(OnDoQuit()));
//    QObject::connect(&logindlg, SIGNAL(accepted()), SLOT(showNormal()));
//    QObject::connect(this, SIGNAL(receiveLoginFailed()),
//                     &logindlg, SLOT(OnLoginFailed()));
//    QObject::connect(this, SIGNAL(receiveLoginError()),
//                     &logindlg, SLOT(OnLoginFailed()));
//    QObject::connect(this, SIGNAL(receiveLoginOK(MsgBusParam)),
//                     &logindlg, SLOT(OnLoginOK(MsgBusParam)));
//    QObject::connect(this, SIGNAL(accepted()),
//                     &logindlg, SLOT(reject()));


    m_is_inloginsession = false;
    m_waitingverify_sendmsg = false;
    m_waitingverify_sendfile = false;

}
void QTIMReceiverDlg::InitMsgHandler()
{
    AddHandler("im.frontend.imreceiver.textmsg", &QTIMReceiverDlg::OnTextMsg, 0);
    AddHandler("im.frontend.imreceiver.reqquit", &QTIMReceiverDlg::OnReqQuit, 0);
    AddHandler("im.frontend.group2contacts.infoready", &QTIMReceiverDlg::OnIMContactsReady, 0);
    AddHandler("im.frontend.imreceiver.addcontact.addedbyother", &QTIMReceiverDlg::OnIMAddContactAddedByOther, 0);
    AddHandler("im.frontend.imreceiver.addcontact.askaddrequest", &QTIMReceiverDlg::OnIMAddContactAskAddRequest, 0);
    AddHandler("im.frontend.imreceiver.addcontact.deniedbyother", &QTIMReceiverDlg::OnIMAddContactDeniedByOther, 0);
    AddHandler("im.frontend.imreceiver.addcontact.agreeaddbyother", &QTIMReceiverDlg::OnIMAddContactAgreeAddByOther, 0);
    AddHandler("im.frontend.imreceiver.subscription_message", &QTIMReceiverDlg::OnIMSubscriptionMsg, 0);
    AddHandler("im.frontend.imreceiver.needauthcode", &QTIMReceiverDlg::OnIMNeedAuthCode, 0);
    AddHandler("im.frontend.imreceiver.checkauthcode.ok", &QTIMReceiverDlg::OnIMAuthCodeOK, 0);
    AddHandler("im.frontend.imreceiver.checkauthcode.failed", &QTIMReceiverDlg::OnIMAuthCodeFailed, 0);
    AddHandler("im.frontend.imreceiver.login.failed", &QTIMReceiverDlg::OnIMLoginFailed, 0);
    AddHandler("im.frontend.imreceiver.login.ok", &QTIMReceiverDlg::OnIMLoginOK, 0);
    AddHandler("netmsgbus.server.getclient.error", &QTIMReceiverDlg::OnIMMainError, 0);
    AddHandler("netmsgbus.client.connectreceiver.failed", &QTIMReceiverDlg::OnIMMainError, 0);
    AddHandler("im.frontend.imreceiver.login.logout" , &QTIMReceiverDlg::OnIMLogout, 0);
    AddHandler("im.frontend.imreceiver.login.loginerror" , &QTIMReceiverDlg::OnIMLoginError, 0);
    AddHandler("im.frontend.imreceiver.login.kicked" , &QTIMReceiverDlg::OnIMLogout, 0);
    AddHandler("im.frontend.imreceiver.fatalerror" , &QTIMReceiverDlg::OnIMLogout, 0);
    AddHandler("im.frontend.imreceiver.login.neterr" , &QTIMReceiverDlg::OnIMLogout, 0);
    AddHandler("im.frontend.imreceiver.userverifyinfo.update" , &QTIMReceiverDlg::OnIMVerifyUserUpdate, 0);
    AddHandler("im.frontend.imreceiver.userverifyinfo.updateforaddcontact" , &QTIMReceiverDlg::OnIMVerifyUserUpdateForAddContact, 0);
    AddHandler("im.frontend.imreceiver.doexportbinmsgs.rsp", &QTIMReceiverDlg::OnIMExportBinMsgsRsp, 0);

}

QTIMReceiverDlg::~QTIMReceiverDlg()
{
    NotifyQuitToWWMain();
    delete ui;
    delete phealth_timer;
    m_all_authcodedlg.clear();
}

void QTIMReceiverDlg::GetAllContacts(QStringList& allcontacts)
{
    allcontacts.clear();
    ContactContainerT::const_iterator cit = m_all_contacts.begin();
    while(m_all_contacts.end() != cit)
    {
        allcontacts.push_back(QString::fromStdString(cit->first));
        ++cit;
    }
}

void QTIMReceiverDlg::CleanDataOnLogout()
{
    m_all_authcodedlg.clear();
    m_all_group2contacts.clear();
    m_all_contacts.clear();

    ui->all_contact_listwidget->clear();
    ui->recent_contact_list->clear();
    ui->sendto_contact_name->clear();
    ui->sysmsg_output->clear();
    ui->tag_filter_comb->clear();
    ui->text_inputer->clear();
    ui->text_receive_viewer->clear();
    ui->text_send_viewer->clear();
    ui->addcontact_name->clear();
    ui->global_errinfo->clear();
    g_all_verifyinfo.clear();
}

void QTIMReceiverDlg::OnSendAuthCode(std::string session, std::string authcode)
{
    core::XParam authcode_info;
    authcode_info.put_Str("session", session);
    authcode_info.put_Str("authcode", authcode);
    NetMsgBus::NetMsgBusSendMsg(m_wwmain_unique, "im.frontend.sendauthcode", CustomType2Param(authcode_info), SendDirectToClient);
}

void QTIMReceiverDlg::OnDoLogin(std::string userid, std::string pass, int loginstate)
{
    core::XParam logininfo;
    logininfo.put_Str("userid", userid);
    logininfo.put_Str("pass", pass);
    logininfo.put_Int("loginstate", loginstate);
    NetMsgBus::NetMsgBusSendMsg(m_wwmain_unique, "im.frontend.dologin", CustomType2Param(logininfo), SendDirectToClient);
    pass.clear();
}

void QTIMReceiverDlg::OnDoLogout()
{
    assert(m_is_inloginsession);
    NetMsgBus::NetMsgBusSendMsg(m_wwmain_unique, "im.frontend.dologout", BuildinType2Param(1), SendDirectToClient);
}

void QTIMReceiverDlg::OnDoQuit()
{
    //OnDoLogout();
    NotifyQuitToWWMain();
    //m_real_close = true;
    //close();
}
void QTIMReceiverDlg::OnDoVerifyUser(std::string uid, int type)
{
    assert(m_is_inloginsession);
    if(m_all_contacts.find(uid) != m_all_contacts.end())
    {
        assert(0);
//        IMUserVerifyInfo verifyinfo;
//        verifyinfo.m_uid = uid;
//        verifyinfo.m_verifyflag = ADDEDAUTH_NONE;
//        if(type == 0)
//            emit receiveVerifyUpdateForAddContact(CustomType2Param(verifyinfo));
//        else
//            emit receiveVerifyUpdate(CustomType2Param(verifyinfo));
//        return;
    }
    core::XParam vinfo;
    vinfo.put_Str("verifyname", uid);
    vinfo.put_Int("verifytype", type);
    NetMsgBus::NetMsgBusSendMsg(m_wwmain_unique, "im.frontend.verifyuser.req", CustomType2Param(vinfo), SendDirectToClient);
}
void QTIMReceiverDlg::OnDoAgreeAddAndAddHim(std::string uid)
{
    OnDoAgreeAdd(uid);
    emit OnDoAddContact(uid);
}

void QTIMReceiverDlg::OnDoAgreeAdd(std::string uid)
{
    core::XParam replyinfo;
    replyinfo.put_Str("replyuid", uid);
    replyinfo.put_Bool("replyagree", true);
    NetMsgBus::NetMsgBusSendMsg(m_wwmain_unique, "im.frontend.dosendreplyaddcontact.req", CustomType2Param(replyinfo), SendDirectToClient);
}

void QTIMReceiverDlg::OnDoDenyAdd(std::string uid)
{
    core::XParam replyinfo;
    replyinfo.put_Str("replyuid", uid);
    replyinfo.put_Bool("replyagree", false);
    replyinfo.put_Str("replyreason", "deny you!");
    NetMsgBus::NetMsgBusSendMsg(m_wwmain_unique, "im.frontend.dosendreplyaddcontact.req", CustomType2Param(replyinfo), SendDirectToClient);
}

void QTIMReceiverDlg::OnDoAddContact(std::string uid)
{
    if(m_all_contacts.find(uid) != m_all_contacts.end())
    {
        ui->global_errinfo->setText("The user is already your friend.");
        pglobal_err_clear_timer->start(5000);
        return;
    }
    if(g_all_verifyinfo.find(uid) == g_all_verifyinfo.end())
    {
        // send verify info first
        OnDoVerifyUser(uid, VERIFYTYPE_ADDCONTACT);
        return;
    }
    std::string reason;
    IMUserVerifyInfo vinfo = g_all_verifyinfo[uid];
    if(vinfo.m_verifyflag == ADDEDAUTH_REQUIRE)
    {
        // show a dialog
        bool ok = false;
        QString text = QInputDialog::getText(this, "Add Contact Reason.", "Reason:", QLineEdit::Normal, "I want Add you as friend", &ok);
        if(ok)
        {
            reason = text.toStdString();
        }
        else
        {
            return;
        }
    }
    else if(vinfo.m_verifyflag == ADDEDAUTH_DENYALL)
    {
        ui->global_errinfo->setText("The user deny anyone to add him as friend.");
        pglobal_err_clear_timer->start(5000);
        return;
    }
    else if(vinfo.m_verifyflag == ADDEDAUTH_NOUID)
    {
        ui->global_errinfo->setText("The user doesn't exist.");
        pglobal_err_clear_timer->start(5000);
        return;
    }
    else if(vinfo.m_verifyflag == ADDEDAUTH_QUESTION)
    {
        // show a dialog
        bool ok = false;
        QString text = QInputDialog::getText(this, "Answer the Question.", "Question:" + QString::fromStdString(vinfo.m_question),
                                             QLineEdit::Normal, "", &ok);
        if(ok)
        {
            reason = text.toStdString();
        }
        else
        {
            return;
        }
    }

    core::XParam addinfo;
    addinfo.put_Str("adduid", uid);
    addinfo.put_Str("addgname", ui->tag_filter_comb->currentText().toStdString());
    addinfo.put_Int("authtype", vinfo.m_verifyflag);
    addinfo.put_Str("addreason", reason);
    NetMsgBus::NetMsgBusSendMsg(m_wwmain_unique, "im.frontend.doaddnewcontact.req", CustomType2Param(addinfo), SendDirectToClient);

    g_all_verifyinfo.erase(uid);
}
void QTIMReceiverDlg::OnGlobalErrClear()
{
    pglobal_err_clear_timer->stop();
    ui->global_errinfo->setText("");
}

void QTIMReceiverDlg::OnHealthCheck()
{
    NetMsgBus::NetMsgBusSendMsg(m_wwmain_unique, "netmsgbus.client.immain.healthcheck", BuildinType2Param(1), SendDirectToClient);
}

void QTIMReceiverDlg::OnSetDestUser(QString userid)
{
    ui->sendto_contact_name->setText(userid);
}

void QTIMReceiverDlg::OnAddContactClicked()
{
    std::string adduid = ui->addcontact_name->text().toStdString();
    if(adduid.empty())
    {
        ui->global_errinfo->setText("please input the user name you want to add.");
        pglobal_err_clear_timer->start(5000);
        return;
    }
    OnDoAddContact(adduid);
}

void QTIMReceiverDlg::OnAnchorClicked(QUrl url)
{
    QString str_url = url.toString();
    if(str_url.indexOf("#userid") == 0)
        ui->sendto_contact_name->setText(url.toString().mid(QString("#userid").size()));
    else if(str_url.indexOf("#AgreeAddAndAddHim") == 0)
    {
        std::string adduid = str_url.mid(QString("#AgreeAddAndAddHim").size()).toStdString();
        OnDoAgreeAddAndAddHim(adduid);
    }
    else if(str_url.indexOf("#AgreeAdd") == 0)
    {
        // agree add friend by other
        std::string adduid = str_url.mid(QString("#AgreeAdd").size()).toStdString();
        OnDoAgreeAdd(adduid);
    }
    else if(str_url.indexOf("#AddHim") == 0)
    {
        std::string adduid = str_url.mid(QString("#AddHim").size()).toStdString();
        OnDoAddContact(adduid);
    }
    else if(str_url.indexOf("#DenyAdd") == 0)
    {
        std::string adduid = str_url.mid(QString("#DenyAdd").size()).toStdString();
        OnDoDenyAdd(adduid);
    }
    else
    {
        //printf("open url :%s\n", url.toString().toStdString().c_str());
        QDesktopServices::openUrl(url);
    }
}
void QTIMReceiverDlg::OnContactListItemClicked(QListWidgetItem *pitem)
{
    ui->sendto_contact_name->setText(pitem->data(Qt::UserRole).toString());
}

void QTIMReceiverDlg::OnSendFileClicked()
{
    core::XParam xp;
    std::string suid = ui->sendto_contact_name->text().trimmed().toUtf8().constData();


    if(suid.empty())
        return;
    m_waitingverify_sendfile = false;
    if(m_all_contacts.find(suid) == m_all_contacts.end())
    {
        // not my friend, verify user first.
        if(g_all_verifyinfo.find(suid) == g_all_verifyinfo.end())
        {
            m_waitingverify_sendfile = true;
            // send verify info first
            OnDoVerifyUser(suid, VERIFYTYPE_CHECKSENDMSG);
            return;
        }
        std::string reason;
        IMUserVerifyInfo vinfo = g_all_verifyinfo[suid];
        if(vinfo.m_verifyflag != ADDEDAUTH_NONE)
        {
            if(vinfo.m_verifyflag == ADDEDAUTH_NOUID)
            {
                ui->global_errinfo->setText("The user doesn't exist.");
            }
            else
            {
                ui->global_errinfo->setText("You can not send file to the user. The User Required You add him as friend first.");
            }
            pglobal_err_clear_timer->start(3000);
            return;
        }
        g_all_verifyinfo.erase(suid);
    }
    QStringList savedpathlist = QFileDialog::getOpenFileNames(this, "select file(s) to send");
    if(savedpathlist.size() < 1)
        return;
    QStringList::iterator it = savedpathlist.begin();
    while(it != savedpathlist.end())
    {
        xp.put_Str(std::string("uid"), suid);
        xp.put_Str(std::string("filename"), (*it).toStdString());
        NetMsgBus::NetMsgBusSendMsg(m_wwmain_unique, "im.frontend.filetransfer.dosendfile.req", CustomType2Param(xp), SendDirectToClient);
        ++it;
    }
}

void QTIMReceiverDlg::OnSendMsgClicked()
{
    core::XParam xp;

    std::string suid = ui->sendto_contact_name->text().trimmed().toUtf8().constData();
    std::string scontent = ui->text_inputer->toPlainText().toUtf8().constData();
    if(suid.empty() || scontent.empty())
        return;
    if(suid == m_loginuid)
    {
        ui->global_errinfo->setText("You can not send to youself.");
        pglobal_err_clear_timer->start(3000);
        return;
    }
    m_waitingverify_sendmsg = false;
    if(m_all_contacts.find(suid) == m_all_contacts.end())
    {
        // not my friend, verify user first.
        if(g_all_verifyinfo.find(suid) == g_all_verifyinfo.end())
        {
            // send verify info first
            m_waitingverify_sendmsg = true;
            OnDoVerifyUser(suid, VERIFYTYPE_CHECKSENDMSG);
            return;
        }
        std::string reason;
        IMUserVerifyInfo vinfo = g_all_verifyinfo[suid];
        if(vinfo.m_verifyflag != ADDEDAUTH_NONE)
        {
            if(vinfo.m_verifyflag == ADDEDAUTH_NOUID)
            {
                ui->global_errinfo->setText("The user doesn't exist.");
            }
            else
            {
                ui->global_errinfo->setText("You can not send message to the user. The User Required You add him as friend first.");
            }
            pglobal_err_clear_timer->start(3000);
            return;
        }
        g_all_verifyinfo.erase(suid);
    }
    xp.put_Str(std::string("uid"), suid);
    xp.put_Str(std::string("content"), scontent);
    NetMsgBus::NetMsgBusSendMsg(m_wwmain_unique, "im.frontend.sendmsg", CustomType2Param(xp), SendDirectToClient);
    ui->text_inputer->clear();
    ui->text_inputer->setFocus();
}

void QTIMReceiverDlg::OnReceiveLoginOK(MsgBusParam param)
{
    Param2CustomType(param, m_loginuid);
    emit notifyLoginOKUid(m_loginuid);
}

void QTIMReceiverDlg::OnFilterTagChanged(QString tagname)
{
    std::map<string, ContactContainerT>::const_iterator cit = m_all_group2contacts.find(tagname.toStdString());
    ContactContainerT contacts_with_tag;
    if(cit != m_all_group2contacts.end())
    {
        contacts_with_tag = cit->second;
    }
    else
    {
        contacts_with_tag = m_all_contacts;
    }
    FillContactDataToContactListWidget(contacts_with_tag);
}
void QTIMReceiverDlg::OnReceiveVerifyUpdateForAddContact(MsgBusParam param)
{
    IMUserVerifyInfo verifyinfo;
    Param2CustomType(param, verifyinfo);
    g_all_verifyinfo[verifyinfo.m_uid] = verifyinfo;
    OnDoAddContact(verifyinfo.m_uid);
}

void QTIMReceiverDlg::OnReceiveVerifyUpdate(MsgBusParam param)
{
    IMUserVerifyInfo verifyinfo;
    Param2CustomType(param, verifyinfo);
    g_all_verifyinfo[verifyinfo.m_uid] = verifyinfo;
    if(m_waitingverify_sendmsg)
        OnSendMsgClicked();
    if(m_waitingverify_sendfile)
        OnSendFileClicked();
}

//void QTIMReceiverDlg::OnReceiveLogout()
//{
//    close();

//    if(QDialog::Accepted == logindlg.exec())
//    {
//        show();
//    }
//}

//void QTIMReceiverDlg::OnReceiveLoginError()
//{
////    close();
//    if(!m_is_inloginsession)
//    {
//        emit receiveLoginFailed("login failed.");
//        return;
//    }
//    m_is_inloginsession = false;

////    if(QDialog::Accepted == logindlg.exec())
////    {
////        show();
////        logindlg.setLoginErrInfo("something error, disconnect from server.");
////    }
//}

void QTIMReceiverDlg::OnReceiveAddContactAskAddRequest(MsgBusParam param)
{
    emit newactivity();
    core::XParam addinfo;
    Param2CustomType(param, addinfo);
    std::string addeduserid;
    addinfo.get_Str("adduid", addeduserid);
    std::string notemsg;
    addinfo.get_Str("addnotemsg", notemsg);
    ui->sysmsg_output->moveCursor(QTextCursor::End);
    // 需要我验证添加
    ui->sysmsg_output->insertHtml("<br/>" + HtmlFormatHelper::FormatUserId(addeduserid) +
                                  "  want to add you as friend. note: " + QString::fromStdString(notemsg) +
                                  HtmlFormatHelper::FormatAddedFriendOperation(addeduserid, AddHim|AgreeAdd|DenyAdd) + "<br/>");
    ui->sysmsg_output->moveCursor(QTextCursor::End);
}
void QTIMReceiverDlg::OnReceiveAddContactDeniedByOther(MsgBusParam param)
{
    emit newactivity();
    core::XParam addinfo;
    Param2CustomType(param, addinfo);
    std::string addeduserid;
    addinfo.get_Str("adduid", addeduserid);
    std::string notemsg;
    addinfo.get_Str("addnotemsg", notemsg);
    ui->sysmsg_output->moveCursor(QTextCursor::End);
    ui->sysmsg_output->insertHtml("<br/>"+ HtmlFormatHelper::FormatUserId(addeduserid) +
                                  "  denied the add as friend request. note: " + QString::fromStdString(notemsg) + "<br/>");
    ui->sysmsg_output->moveCursor(QTextCursor::End);
    g_all_verifyinfo.erase(addeduserid);
}

void QTIMReceiverDlg::OnReceiveAddContactAgreeAddByOther(MsgBusParam param)
{
    emit newactivity();
    core::XParam addinfo;
    Param2CustomType(param, addinfo);
    std::string addeduserid;
    addinfo.get_Str("adduid", addeduserid);
    std::string gname;
    addinfo.get_Str("addgname", gname);
    core::XParam contactinfoxp;
    addinfo.get_XParam("contactinfo", contactinfoxp);
    S_ContactInfo contactinfo;
    contactinfo.FromXParam(contactinfoxp);
    ui->sysmsg_output->moveCursor(QTextCursor::End);

    ui->sysmsg_output->insertHtml("<br/>" + HtmlFormatHelper::FormatUserId(addeduserid) +
                                  "  has agreed you add him as friend. <br/>");

    ui->sysmsg_output->moveCursor(QTextCursor::End);
    ui->global_errinfo->setText("add " + QString::fromStdString(addeduserid) + " as friend sucess.");
    pglobal_err_clear_timer->start(3000);
    m_all_contacts[addeduserid] = contactinfo;
    m_all_group2contacts[gname][addeduserid] = contactinfo;
    OnFilterTagChanged(QString::fromStdString(gname));
    g_all_verifyinfo.erase(addeduserid);
}
void QTIMReceiverDlg::OnReceiveAddContactAddedByOther(MsgBusParam param)
{
    emit newactivity();
    core::XParam addinfo;
    Param2CustomType(param, addinfo);
    std::string addeduserid;
    addinfo.get_Str("adduid", addeduserid);
    ui->sysmsg_output->moveCursor(QTextCursor::End);
    if(m_all_contacts.find(addeduserid) != m_all_contacts.end())
    {
        // this user is already my friend, so just show add info
        ui->sysmsg_output->insertHtml("<br/>" + HtmlFormatHelper::FormatUserId(addeduserid) + "  added you as friend. " + "<br/>");
    }
    else
    {
        // 不需要验证的被添加, 因此不需要再显示允许或拒绝添加选项了
        ui->sysmsg_output->insertHtml("<br/>" + HtmlFormatHelper::FormatUserId(addeduserid) + "  added you as friend. " +
                                      HtmlFormatHelper::FormatAddedFriendOperation(addeduserid, AddHim) + "<br/>");
    }
    ui->sysmsg_output->moveCursor(QTextCursor::End);
}

void QTIMReceiverDlg::OnReceiveSubscriptionMsg(MsgBusParam param)
{
    emit newactivity();
    IMSubscriptionMessage sm;
    Param2CustomType(param, sm);
    QString substr;
    substr = "<br/>" + QString::fromStdString(sm.maintitle_) + "-" + QString::fromStdString(sm.title_) +
            "  " + QString::fromStdString(sm.time_) + "<br/>" + QString::fromStdString(sm.content_ + sm.message_) + "<br/>";
    ui->sysmsg_output->moveCursor(QTextCursor::End);
    ui->sysmsg_output->insertHtml(substr);
    ui->sysmsg_output->moveCursor(QTextCursor::End);
    // test only
//    core::XParam testxp;
//    testxp.put_Str("session", CommonUtility::GenerateGuidStr());

//    qRegisterMetaType<MsgBusParam>("MsgBusParam");
//    emit receiveNeedAuthCode(CustomType2Param(testxp));
}

void QTIMReceiverDlg::OnReceiveNeedAuthCode(MsgBusParam param)
{
    core::XParam authinfo;
    Param2CustomType(param, authinfo);

    std::string sessionid;
    authinfo.get_Str("session", sessionid);

    boost::shared_ptr<IMSecurityCodeDlg> spSecurityDlg(new IMSecurityCodeDlg());
    m_all_authcodedlg[sessionid] = spSecurityDlg;
    QObject::connect(spSecurityDlg.get(), SIGNAL(sendAuthCode(std::string,std::string)), SLOT(OnSendAuthCode(std::string,std::string)));
    QObject::connect(spSecurityDlg.get(), SIGNAL(cancelAuthCode(std::string)), SLOT(OnCancelAuthCode(std::string)));
    spSecurityDlg->SetAuthCodeSession(sessionid);
    spSecurityDlg->show();

}
void QTIMReceiverDlg::OnCancelAuthCode(std::string session)
{
    m_all_authcodedlg.erase(session);
}

void QTIMReceiverDlg::OnReceiveAuthCodeFailed(std::string session)
{
    if(m_all_authcodedlg.find(session) != m_all_authcodedlg.end())
        m_all_authcodedlg[session]->SetAuthStateInfo("auth code not matched.please retry.");
}

void QTIMReceiverDlg::OnReceiveAuthCodeOK(std::string session)
{
    m_all_authcodedlg.erase(session);
}

void QTIMReceiverDlg::FillContactDataToContactListWidget(wwbiz::ContactContainerT contacts)
{
    ui->all_contact_listwidget->clear();
    // add the contacts to all contacts list widget
    ContactContainerT::const_iterator contactit = contacts.begin();
    while(contactit != contacts.end())
    {
        QListWidgetItem *item = new QListWidgetItem(QString::fromStdString(contactit->second.m_dispName));
        item->setData(Qt::UserRole, QString::fromStdString(contactit->second.m_contactuid));
        ui->all_contact_listwidget->addItem(item);
        ++contactit;
    }
}

void QTIMReceiverDlg::OnReceiveContacts(MsgBusParam param)
{
    emit newactivity();
    ui->tag_filter_comb->clear();
    MsgBusParam2GroupContactInfo(param, m_all_group2contacts);
    std::map<string, ContactContainerT>::const_iterator cit = m_all_group2contacts.begin();
    // add a default group stand for all contacts.
    ui->tag_filter_comb->addItem("");
    while(cit != m_all_group2contacts.end())
    {
        // add group name to combox
        ui->tag_filter_comb->addItem(QString::fromStdString(cit->first));
        m_all_contacts.insert(cit->second.begin(), cit->second.end());
        ++cit;
    }
    // add the contacts under the group to all contacts list widget
    FillContactDataToContactListWidget(m_all_contacts);
    ReadRecentContactFromFile();
}

void QTIMReceiverDlg::AppendMsgsAndScroll(const QString& htmlStr, bool issendbyother)
{
    if(issendbyother)
    {
        int current_pos = ui->text_receive_viewer->verticalScrollBar()->value();
        int oldmax = ui->text_receive_viewer->verticalScrollBar()->maximum();

        ui->text_receive_viewer->moveCursor(QTextCursor::End);
        ui->text_receive_viewer->insertHtml(htmlStr);
        ui->text_receive_viewer->moveCursor(QTextCursor::End);
        if(current_pos >= oldmax)
        {
            ui->text_receive_viewer->verticalScrollBar()->setValue(ui->text_receive_viewer->verticalScrollBar()->maximum());
        }
        else
        {
            ui->text_receive_viewer->verticalScrollBar()->setValue(current_pos);
        }
    }
    else
    {
        int current_pos = ui->text_send_viewer->verticalScrollBar()->value();
        int oldmax = ui->text_send_viewer->verticalScrollBar()->maximum();
        ui->text_send_viewer->moveCursor(QTextCursor::End);
        ui->text_send_viewer->insertHtml(htmlStr);
        ui->text_send_viewer->moveCursor(QTextCursor::End);
        if(current_pos >= oldmax)
        {

            ui->text_send_viewer->verticalScrollBar()->setValue(ui->text_send_viewer->verticalScrollBar()->maximum());
        }
        else
        {
            ui->text_send_viewer->verticalScrollBar()->setValue(current_pos);
        }
    }
}

void QTIMReceiverDlg::OnOfflineImageNotify(MsgBusParam param)
{
    ui->text_receive_viewer->update();
    AppendMsgsAndScroll("&nbsp;", true);
    //ui->text_receive_viewer->append("");
}

void QTIMReceiverDlg::OnPicTransferFinished(MsgBusParam param)
{
    // just insert the picture to the view
//    core::XParam xp;
//    Param2CustomType(param, xp);
//    std::string uid, imgname;
//    xp.get_Str("uid", uid);
//    xp.get_Str("imgname", imgname);
//    QString htmlStr = QString("<br />%1 : <br /> %2 <br />").arg(HtmlFormatHelper::FormatUserId(uid))
//                    .arg(HtmlFormatHelper::FormatPictureMsg(imgname));
//    AppendMsgsAndScroll(htmlStr, true);
    //printf("text view refreshed for picture finished.\n");
    //ui->text_receive_viewer->update();
    ui->text_receive_viewer->update();
    AppendMsgsAndScroll("&nbsp", true);
    //ui->text_receive_viewer->append("");
}

void QTIMReceiverDlg::OnReceiveMsgs(MsgBusParam param)
{
    emit newactivity();

    IMTextMessageVector msgvec;
    Param2CustomType(param, msgvec);
    // test image insert
    //ui->text_receive_viewer->append("<a href=\"file:////Users/absolute/Desktop/11.png\"><img src=\"/Users/absolute/Desktop/11.png\" /></a>");
    //printf("image html:%s.\n", ui->text_receive_viewer->toHtml().toStdString().c_str());
    for(size_t i = 0; i < msgvec.size(); i++)
    {
        const IMTextMessage& msg = msgvec[i];
        QString timestr = HtmlFormatHelper::FormatTime(msg.time_);

        std::string msguid;
        // append message to message viewer
        // if any picture was sended, when the picture finished, it will be inserted to view.
        if(msg.bsend_)
        {
            QString htmlStr = QString("<br/>%1 : %2 <br/> %3 %4 ")
                    .arg(HtmlFormatHelper::FormatUserId(msg.fromuid_))
                    .arg(timestr)
                    .arg(HtmlFormatHelper::FormatMessageContent(msg.text_))
                    .arg(HtmlFormatHelper::FormatAllPicturesToHtml(msg.message_));

            AppendMsgsAndScroll(htmlStr, msg.bsend_);
            msguid = msg.fromuid_;
            QSound::play("resources/newmsg.wav");
        }
        else
        {
            QString htmlStr = QString("<br/>@%1 : %2 <br/> %3 %4")
                    .arg(HtmlFormatHelper::FormatUserId(msg.id_))
                    .arg(timestr)
                    .arg(HtmlFormatHelper::FormatMessageContent(msg.text_))
                    .arg(HtmlFormatHelper::FormatAllPicturesToHtml(msg.message_));
            AppendMsgsAndScroll(htmlStr, msg.bsend_);
            msguid = msg.id_;
        }
        QString qmsguid = QString::fromStdString(msguid);
        QString qnickname = QString::fromStdString(msguid);
        if(m_all_contacts.find(msguid) != m_all_contacts.end())
        {
            qnickname = QString::fromStdString(m_all_contacts[msguid].m_dispName);
        }
        // update recent contact user list
        int totalrecent = ui->recent_contact_list->count();
        //int pos = -1;
        QList<QListWidgetItem*> matchItems = ui->recent_contact_list->findItems(qnickname, Qt::MatchFixedString|Qt::MatchCaseSensitive);
        if(matchItems.size() != 0)
        {
            QList<QListWidgetItem*>::iterator it = matchItems.begin();
            while(it != matchItems.end())
            {
                if((*it)->data(Qt::UserRole).toString() == qmsguid)
                {
                    if(ui->recent_contact_list->row(*it) != 0)
                    {// not the first , we need put this contact to the first
                        QListWidgetItem *item = ui->recent_contact_list->takeItem(ui->recent_contact_list->row(*it));
                        ui->recent_contact_list->insertItem(0, item);
                        UpdateRecentContactToFile();
                    }
                    break;
                }
                ++it;
            }
        }
        else
        {
            // new recent
            if(totalrecent > RECENT_CONTACT_MAX)
            {// too many, we need delete the last contact
                QListWidgetItem * ritem = ui->recent_contact_list->takeItem(totalrecent - 1);
                delete ritem;
            }
            QListWidgetItem *item = new QListWidgetItem(qnickname);
            item->setData(Qt::UserRole, qmsguid);
            ui->recent_contact_list->insertItem(0, item);
            UpdateRecentContactToFile();
        }
    }

}
void QTIMReceiverDlg::ReadRecentContactFromFile()
{
    QString profiledir = QString::fromStdString(FileUtility::MakeWWProfileForUser(m_loginuid));
    QFile recentfile(profiledir + "/recent_contact");
    if(recentfile.open(QFile::ReadOnly))
    {
        ui->recent_contact_list->clear();
        QTextStream rs(&recentfile);
        QString line = rs.readLine();
        while(!line.isNull())
        {
            QString dispName = line;
            if(m_all_contacts.find(line.toStdString()) != m_all_contacts.end())
            {
                dispName = QString::fromStdString(m_all_contacts[line.toStdString()].m_dispName);
            }
            QListWidgetItem *item = new QListWidgetItem(dispName);
            item->setData(Qt::UserRole, line);
            ui->recent_contact_list->addItem(item);
            line = rs.readLine();
        }
    }
}

void QTIMReceiverDlg::UpdateRecentContactToFile()
{
    QString profiledir = QString::fromStdString(FileUtility::MakeWWProfileForUser(m_loginuid));
    QFile recentfile(profiledir + "/recent_contact");
    if(recentfile.open(QFile::WriteOnly|QFile::Truncate))
    {
        QTextStream ws(&recentfile);

        int cnt = ui->recent_contact_list->count();
        for(int i = 0; i < cnt;i++)
        {
            ws << ui->recent_contact_list->item(i)->data(Qt::UserRole).toString() << "\n";
        }
    }
    else
    {
        QMessageBox::information(this, "open file error", "open file for write recent contact error.");
    }
}

void QTIMReceiverDlg::NotifyQuitToWWMain()
{
    NetMsgBus::NetMsgBusSendMsg(m_wwmain_unique, "im.frontend.imreceiver.closed", BuildinType2Param(1), SendDirectToClient);
}

void QTIMReceiverDlg::NotifyReadyToWWMain()
{
    NetMsgBus::NetMsgBusSendMsg(m_wwmain_unique, "im.frontend.imreceiver.ready", BuildinType2Param(1), SendDirectToClient);
    // start health check timer
    phealth_timer->start(3000);
}

void QTIMReceiverDlg::SetWWMainUniqueFlag(const std::string& unique)
{
    m_wwmain_unique = unique;
}

bool QTIMReceiverDlg::OnReqQuit(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    printf("receive quit req.\n");
    phealth_timer->stop();
    //m_real_close = true;
    //close();
    emit immainerror();
    return true;
}

bool QTIMReceiverDlg::OnIMMainError(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    std::string clientname;
    Param2CustomType(param, clientname);
    printf("begin quit since the main im is not detected.\n");
    if(clientname == m_wwmain_unique)
    {
        //m_real_close = true;
        // 旺旺主程序可能已经异常退出
        //close();
        phealth_timer->stop();
        emit immainerror();
    }
    return true;
}

bool QTIMReceiverDlg::OnTextMsg(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    emit receiveMsgs(param);
    return true;
}

bool QTIMReceiverDlg::OnIMContactsReady(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    g_log.Log(lv_debug, "receive contacts ready info");
    emit receiveContacts(param);
    return true;
}

bool QTIMReceiverDlg::OnIMAddContactAddedByOther(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    emit receiveAddContactAddedByOther(param);
    return true;
}
bool QTIMReceiverDlg::OnIMAddContactAskAddRequest(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    emit receiveAddContactAskAddRequest(param);
    return true;
}
bool QTIMReceiverDlg::OnIMAddContactDeniedByOther(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    emit receiveAddContactDeniedByOther(param);
    return true;
}
bool QTIMReceiverDlg::OnIMAddContactAgreeAddByOther(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    emit receiveAddContactAgreeAddByOther(param);
    return true;
}
bool QTIMReceiverDlg::OnIMSubscriptionMsg(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    emit receiveSubscriptionMsg(param);
    return true;
}
bool QTIMReceiverDlg::OnIMNeedAuthCode(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    emit receiveNeedAuthCode(param);
    return true;
}

bool QTIMReceiverDlg::OnIMAuthCodeOK(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    core::XParam info;
    Param2CustomType(param, info);
    std::string session;
    info.get_Str("session", session);
    emit receiveAuthCodeOK(session);

    return true;
}
bool QTIMReceiverDlg::OnIMAuthCodeFailed(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    core::XParam info;
    Param2CustomType(param, info);
    std::string session;
    info.get_Str("session", session);
    emit receiveAuthCodeFailed(session);
    return true;
}

bool QTIMReceiverDlg::OnIMLoginFailed(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    m_is_inloginsession = false;
    emit receiveLoginFailed("login failed because of auth failed.");
    return true;
}
bool QTIMReceiverDlg::OnIMLoginOK(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    m_is_inloginsession = true;

    g_log.Log(lv_debug, "receive loginok info");
    emit receiveLoginOK(param);
    return true;
}

bool QTIMReceiverDlg::OnIMLogout(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    m_is_inloginsession = false;
    if(msgid == "im.frontend.imreceiver.login.kicked")
    {
        emit receiveLoginError("logout, kicked by other.");
    }
    else if(msgid == "im.frontend.imreceiver.login.neterr")
    {
        emit receiveLoginError("logout, network error");
    }
    else
    {
        emit receiveLoginError("");
    }
    emit receiveLogout();
    return true;
}

bool QTIMReceiverDlg::OnIMLoginError(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    if(m_is_inloginsession)
        emit receiveLoginError("force disconnect from server.");
    else
        emit receiveLoginFailed("login failed.");
    return true;
}

bool QTIMReceiverDlg::OnIMVerifyUserUpdate(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    emit receiveVerifyUpdate(param);
    return true;
}

bool QTIMReceiverDlg::OnIMVerifyUserUpdateForAddContact(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    emit receiveVerifyUpdateForAddContact(param);
    return true;
}

void QTIMReceiverDlg::OnViewHistoryClicked()
{
    //
    if(!m_is_inloginsession)
        return;
    core::XParam xp;

    NetMsgBus::NetMsgBusSendMsg(m_wwmain_unique, "im.frontend.doexportbinmsgs.req", CustomType2Param(xp), SendDirectToClient);
    emit openHistoryView();
}
bool QTIMReceiverDlg::OnIMExportBinMsgsRsp(const std::string& msgid, MsgBusParam& param, bool& is_continue)
{
    emit receiveHistoryData(param);
    return true;
}

void QTIMReceiverDlg::on_btnSendPic_clicked()
{
    core::XParam xp;
    std::string suid = ui->sendto_contact_name->text().trimmed().toUtf8().constData();

    if(suid.empty())
        return;
    m_waitingverify_sendfile = false;
    if(m_all_contacts.find(suid) == m_all_contacts.end())
    {
        // not my friend .
        ui->global_errinfo->setText("send picture failed, not your friend.");
        pglobal_err_clear_timer->start(5000);
        return;
    }
    QStringList savedpathlist = QFileDialog::getOpenFileNames(this, "select picture(s) to send", "", "Images(*.png *.jpg *.jpeg *.bmp *.gif)");
    if(savedpathlist.size() < 1)
        return;
    else if(savedpathlist.size() > 5)
    {
        ui->global_errinfo->setText("you can only send 5 pictures once at most. ");
        pglobal_err_clear_timer->start(5000);
        return;
    }
    QStringList::iterator it = savedpathlist.begin();
    while(it != savedpathlist.end())
    {
        xp.put_Str(std::string("uid"), suid);
        xp.put_Str(std::string("filename"), (*it).toStdString());
        xp.put_Int(std::string("filetype"), 0x08);
        NetMsgBus::NetMsgBusSendMsg(m_wwmain_unique, "im.frontend.filetransfer.offlinefile.dosendfile.req", CustomType2Param(xp), SendDirectToClient);
        ++it;
    }
}
